package com.yyy.tcc.service.compensation;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 展示线程池的优势，并详细展示JVM中的线程层级结构
 */
public class PoolBenefitsDemo {
    private static final Logger log = LoggerFactory.getLogger(PoolBenefitsDemo.class);

    /**
     * 打印线程组的层级结构
     */
    private void printThreadGroupHierarchy() {
        // 1. 获取当前线程组
        ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
        log.info("\n=== 当前线程组信息 ===");
        log.info("当前线程组名称: {}", currentGroup.getName());

        // 获取当前组所有线程
        int threadCount = currentGroup.activeCount();
        Thread[] threads = new Thread[threadCount];
        currentGroup.enumerate(threads, false);

        // 统计守护线程和用户线程
        int daemonCount = 0;
        int userCount = 0;
        for (Thread thread : threads) {
            if (thread != null) {
                if (thread.isDaemon()) {
                    daemonCount++;
                } else {
                    userCount++;
                }
            }
        }

        log.info("当前线程组总线程数: {}", threadCount);
        log.info("|- 守护线程数: {}", daemonCount);
        log.info("|- 用户线程数: {}", userCount);

        // 2. 获取根线程组
        ThreadGroup rootGroup = currentGroup;
        while (rootGroup.getParent() != null) {
            rootGroup = rootGroup.getParent();
        }

        // 3. 打印整个线程组层级结构
        log.info("\n=== 完整的线程组层级结构 ===");
        printGroupDetails(rootGroup, "");
    }

    /**
     * 递归打印线程组详情
     */
    private void printGroupDetails(ThreadGroup group, String indent) {
        // 统计当前组的守护线程和用户线程
        int threadCount = group.activeCount();
        Thread[] threads = new Thread[threadCount];
        int actualCount = group.enumerate(threads, false);  // 获取实际线程数

        // 重置计数器
        int daemonCount = 0;
        int userCount = 0;

        // 只统计实际存在的线程
        for (int i = 0; i < actualCount; i++) {
            Thread thread = threads[i];
            if (thread != null) {  // 额外的空值检查
                if (thread.isDaemon()) {
                    daemonCount++;
                } else {
                    userCount++;
                }
            }
        }

        // 打印当前线程组信息（使用实际统计的数字）
        log.info("{}线程组: [{}] (总线程数: {}, 守护线程: {}, 用户线程: {})",
            indent,
            group.getName(),
            daemonCount + userCount,  // 使用实际统计的总数
            daemonCount,
            userCount
        );

        // 打印每个线程的详细信息
        for (int i = 0; i < actualCount; i++) {
            Thread thread = threads[i];
            if (thread != null) {
                String threadType = thread.isDaemon() ? "守护线程" : "用户线程";
                log.info("{}|- {} : {} (ID: {}, 状态: {}, 优先级: {})",
                    indent + "  ",
                    threadType,
                    thread.getName(),
                    thread.getId(),
                    thread.getState(),
                    thread.getPriority()
                );
            }
        }

        // 递归处理子线程组
        int groupCount = group.activeGroupCount();
        ThreadGroup[] childGroups = new ThreadGroup[groupCount];
        int actualGroupCount = group.enumerate(childGroups, false);

        for (int i = 0; i < actualGroupCount; i++) {
            ThreadGroup childGroup = childGroups[i];
            if (childGroup != null) {
                printGroupDetails(childGroup, indent + "    ");
            }
        }
    }

    /**
     * 不使用线程池的场景
     */
    @Test
    public void withoutThreadPool() throws InterruptedException {
        // 1. 打印初始的线程状态（使用新的统计方法）
        log.info("\n=== 测试开始前的线程状态 ===");
        printTotalThreadStats();

        final int taskCount = 1000;
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(taskCount);

        // 2. 创建线程前记录状态
        log.info("\n=== 创建线程前的状态 ===");
        long startMemory = getUsedMemory();
        int initialThreadCount = getTotalThreadCount();
        log.info("初始内存: {}MB", startMemory / 1024 / 1024);
        log.info("初始线程总数: {}", initialThreadCount);

        // 3. 创建1000个线程
        for (int i = 0; i < taskCount; i++) {
            new Thread(() -> {
                try {
                    startLatch.await();
                    processRequest();
                    successCount.incrementAndGet();
                } catch (Exception e) {
                    failCount.incrementAndGet();
                } finally {
                    endLatch.countDown();
                }
            }, "task-thread-" + i).start();

            // 每创建100个线程打印一次状态
            if (i > 0 && i % 100 == 0) {
                log.info("已创建 {} 个线程, 当前系统状态:", i);
                printTotalThreadStats();
                log.info("当前内存使用: {}MB", (getUsedMemory() - startMemory) / 1024 / 1024);
            }
        }

        // 4. 创建完所有线程后的状态
        log.info("\n=== 创建{}个线程后的状态 ===", taskCount);
        printTotalThreadStats();
        log.info("内存增加: {}MB", (getUsedMemory() - startMemory) / 1024 / 1024);

        // 5. 开始执行任务
        startLatch.countDown();

        // 6. 等待所有任务完成
        boolean completed = endLatch.await(30, TimeUnit.SECONDS);

        // 7. 任务完成后的最终状态
        log.info("\n=== 任务完成后的最终状态 ===");
        log.info("任务是否全部完成: {}", completed);
        log.info("成功任务数: {}", successCount.get());
        log.info("失败任务数: {}", failCount.get());
        printTotalThreadStats();
        log.info("最终内存增加: {}MB", (getUsedMemory() - startMemory) / 1024 / 1024);
    }

    /**
     * 获取系统总线程数（安全的方法）
     */
    private int getTotalThreadCount() {
        try {
            ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
            while (rootGroup.getParent() != null) {
                rootGroup = rootGroup.getParent();
            }

            int estimatedCount = rootGroup.activeCount();
            Thread[] threads = new Thread[estimatedCount * 2];
            int actualCount = rootGroup.enumerate(threads, true);

            // 统计实际的非null线程数
            int validCount = 0;
            for (int i = 0; i < actualCount; i++) {
                if (threads[i] != null) {
                    validCount++;
                }
            }
            return validCount;
        } catch (Exception e) {
            log.error("获取线程总数时发生异常", e);
            return -1;
        }
    }

    /**
     * 模拟请求处理
     */
    private void processRequest() {
        try {
            // 模拟业务处理
            Thread.sleep(10);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 获取已使用内存
     */
    private long getUsedMemory() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }

    /**
     * 获取并打印所有线程的统计信息
     */
    private void printTotalThreadStats() {
        try {
            // 获取根线程组
            ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
            while (rootGroup.getParent() != null) {
                rootGroup = rootGroup.getParent();
            }

            // 获取所有线程
            int estimatedCount = rootGroup.activeCount();
            Thread[] threads = new Thread[estimatedCount * 2];
            int actualCount = rootGroup.enumerate(threads, true);

            // 统计数据
            int totalThreads = 0;
            int totalDaemon = 0;
            int totalUser = 0;

            // 统计有效线程
            for (int i = 0; i < actualCount; i++) {
                Thread thread = threads[i];
                if (thread != null) {
                    totalThreads++;
                    if (thread.isDaemon()) {
                        totalDaemon++;
                    } else {
                        totalUser++;
                    }
                }
            }

            // 只打印统计数据
            log.info("=== 线程统计 ===");
            log.info("总线程数: {}", totalThreads);
            log.info("|- 守护线程: {}", totalDaemon);
            log.info("|- 用户线程: {}", totalUser);

        } catch (Exception e) {
            log.error("统计线程信息时发生异常", e);
        }
    }

    /**
     * 使用线程池的场景
     */
    @Test
    public void withThreadPool() throws InterruptedException {
        // 1. 打印初始状态
        log.info("\n=== 测试开始前的线程状态 ===");
        printTotalThreadStats();

        final int taskCount = 1000;
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(taskCount);

        // 2. 创建线程池前记录状态
        log.info("\n=== 创建线程池前的状态 ===");
        long startMemory = getUsedMemory();
        int initialThreadCount = getTotalThreadCount();
        log.info("初始内存: {}MB", startMemory / 1024 / 1024);
        log.info("初始线程总数: {}", initialThreadCount);

        // 3. 创建线程池 - 修改配置使其更合理
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            50,                     // 减小核心线程数
            100,                     // 减小最大线程数
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),  // 增加队列容量
            r -> {
                Thread t = new Thread(r);
                t.setName("pool-thread-" + t.getId());
                return t;
            },
            (r, e) -> {
                // 自定义拒绝策略：记录失败并继续
                failCount.incrementAndGet();
                log.warn("任务被拒绝执行");
                endLatch.countDown(); // 确保计数器正确
            }
        );

        try {
            // 4. 提交任务前的状态
            log.info("\n=== 提交任务前的状态 ===");
            printTotalThreadStats();
            log.info("线程池初始状态 - 核心线程数: {}, 最大线程数: {}, 队列容量: {}",
                executor.getCorePoolSize(),
                executor.getMaximumPoolSize(),
                executor.getQueue().remainingCapacity()
            );

            // 5. 提交任务
            for (int i = 0; i < taskCount; i++) {
                final int taskId = i;
                try {
                    executor.execute(() -> {
                        try {
                            startLatch.await();
                            processRequest();
                            successCount.incrementAndGet();
                        } catch (Exception e) {
                            log.error("任务-{}执行失败: {}", taskId, e.getMessage());
                            failCount.incrementAndGet();
                        } finally {
                            endLatch.countDown();
                        }
                    });

                    // 每提交100个任务打印一次状态
                    if (i > 0 && i % 100 == 0) {
                        log.info("\n=== 已提交 {} 个任务的状态 ===", i);
                        log.info("活跃线程: {}, 完成任务: {}, 队列任务: {}, 内存使用: {}MB",
                            executor.getActiveCount(),
                            successCount.get(),
                            executor.getQueue().size(),
                            (getUsedMemory() - startMemory) / 1024 / 1024
                        );
                    }
                } catch (Exception e) {
                    log.error("提交任务-{}失败: {}", taskId, e.getMessage());
                    failCount.incrementAndGet();
                    endLatch.countDown();
                }
            }

            // 6. 开始执行
            log.info("\n=== 开始执行任务 ===");
            startLatch.countDown();

            // 7. 等待任务完成
            if (!endLatch.await(30, TimeUnit.SECONDS)) {
                log.warn("部分任务执行超时！");
            }

            // 8. 打印最终状态
            log.info("\n=== 执行完成后的状态 ===");
            log.info("成功任务数: {}", successCount.get());
            log.info("失败任务数: {}", failCount.get());
            log.info("线程池状态:");
            log.info("|- 最大线程数: {}", executor.getLargestPoolSize());
            log.info("|- 活跃线程数: {}", executor.getActiveCount());
            log.info("|- 完成任务数: {}", executor.getCompletedTaskCount());
            log.info("|- 队列任务数: {}", executor.getQueue().size());
            log.info("内存增加: {}MB", (getUsedMemory() - startMemory) / 1024 / 1024);

        } finally {
            // 9. 关闭线程池
            executor.shutdown();
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        }
    }

    /**
     * 对比测试
     */
    @Test
    public void compareThreadPoolVsNoPool() throws InterruptedException {
        log.info("\n========== 不使用线程池的测试 ==========");
        withoutThreadPool();

        Thread.sleep(1000); // 等待系统资源释放

        log.info("\n========== 使用线程池的测试 ==========");
        withThreadPool();

        log.info("\n========== 测试结果对比 ==========");
        log.info("1. 线程池优势:");
        log.info("   - 线程数可控，避免线程爆炸");
        log.info("   - 内存使用更稳定");
        log.info("   - 系统资源利用更合理");
        log.info("   - 任务排队执行，避免系统过载");

        log.info("\n2. 不使用线程池的问题:");
        log.info("   - 线程数量失控");
        log.info("   - 内存消耗大");
        log.info("   - 线程创建和销毁开销大");
        log.info("   - 容易导致系统资源耗尽");

    }
}
